package cn.stylefeng.guns.modular.gridsystem.temperature.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.stylefeng.guns.core.factory.PageFactory;
import cn.stylefeng.guns.core.pojo.page.PageResult;
import cn.stylefeng.guns.modular.gridsystem.entity.BizGateway;
import cn.stylefeng.guns.modular.gridsystem.enums.temp.TempConfigUtil;
import cn.stylefeng.guns.modular.gridsystem.enums.temp.TempDictType;
import cn.stylefeng.guns.modular.gridsystem.service.BizGatewayService;
import cn.stylefeng.guns.modular.gridsystem.temperature.entity.*;
import cn.stylefeng.guns.modular.gridsystem.temperature.mapper.BizTemperatureRecordMapper;
import cn.stylefeng.guns.modular.gridsystem.temperature.model.contants.TempConstant;
import cn.stylefeng.guns.modular.gridsystem.temperature.model.param.BizTemperatureRecordParam;
import cn.stylefeng.guns.modular.gridsystem.temperature.model.result.BizTemperatureRecordResult;
import cn.stylefeng.guns.modular.gridsystem.temperature.service.*;
import cn.stylefeng.guns.sys.modular.timer.tasks.SystemOutTaskRunner;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.util.*;

@Service
@Slf4j
public class BizTemperatureRecordServiceImpl extends ServiceImpl<BizTemperatureRecordMapper, BizTemperatureRecord> implements BizTemperatureRecordService {

    @Autowired
    private BizGatewayService bizGatewayService;

    @Autowired
    private BizTemperatureChannelService bizTemperatureChannelService;

    @Autowired
    private BizTemperatureExceptionService bizTemperatureExceptionService;
    @Autowired
    private BizTemperatureExceptionLogService bizTemperatureExceptionLogService;

    @Override
    public PageResult<BizTemperatureRecordResult> pageList(BizTemperatureRecordParam param) {
        String[] arr = new String[1];

        if (StringUtils.isNotBlank(param.getGatewayIds())) {
            arr = param.getGatewayIds().split(",");
        } else {
            arr[0] = "";
        }
        Page<BizTemperatureRecordResult> page = this.baseMapper.page(PageFactory.defaultPage(), param, arr);
        return new PageResult<>(page);
    }

    //波动异常计数器
    private static Map<String, Integer> COUNT_MAP = new HashMap<>();


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(BizTemperatureRecordParam param) {

        //  List<BizTemperatureRecord> temperatureRecordList = new ArrayList<>();

        String gatewayCode = param.getDeviceCode();
        String tapeTime = param.getNow();
        Map<String, Double> map = param.getTemperatureData();
        Integer gatewayId = bizGatewayService.lambdaQuery().eq(BizGateway::getGatewayCode, gatewayCode).one().getId();

        //设置计数器
        for (String key : map.keySet()) {
            String gatewayChannel = Integer.parseInt(key) + 1 + "";
            //首先根据 gatewayId  gateway_channel确定唯一
            BizTemperatureChannel bizTemperatureChannel = bizTemperatureChannelService.lambdaQuery()
                    .eq(BizTemperatureChannel::getGatewayId, gatewayId)
                    .eq(BizTemperatureChannel::getGatewayChannel, gatewayChannel)
                    .orderByDesc(BizTemperatureChannel::getCreateTime)
                    .last("limit 1")
                    .one();

            //外壳温度
            Double temperature = map.get(key);

            //温度大于 0才是有效的通道
            if (temperature > 0) {
                //保留两位小数 0 表示如果位数不足则以 0 填充，# 表示只要有可能就把数字拉上这个位置
                DecimalFormat df = new DecimalFormat("#.0");
                BizTemperatureRecord record = new BizTemperatureRecord();
                record.setGatewayCode(gatewayCode);
                record.setGatewayId(gatewayId);
                record.setTapeTime(tapeTime);
                record.setGatewayChannel(gatewayChannel);
                record.setCollectTemperature(df.format(temperature));
                //计算实际温度
                Double chaValue = bizTemperatureChannel == null || bizTemperatureChannel.getChaValue() == null ? Double.valueOf(findDIcValue(TempDictType.TEMP_CHA_VALUE.getValue())) : bizTemperatureChannel.getChaValue();
                String formattedValue = df.format(temperature + chaValue);
                record.setTemperature(formattedValue);

                if (ObjectUtil.isNull(bizTemperatureChannel)) {
                    //生成通道初始化【biz_temperature_channel】
                    findInitChannel(bizTemperatureChannel, record);
                }
                //设备温度通道表 【biz_temperature_channel】 已经绑定设备并设置参数的话
                else if (ObjectUtil.isNotNull(bizTemperatureChannel) && ObjectUtil.isNotNull(bizTemperatureChannel.getDeviceId())) {
                    //绑定的值保存到【biz_temperature_record】
                    record.setDeviceId(bizTemperatureChannel.getDeviceId());
                    record.setInstallLocation(bizTemperatureChannel.getInstallLocation());
                    record.setMaxValue(bizTemperatureChannel.getMaxValue() == null ? Double.valueOf( findDIcValue(TempDictType.TEMP_MAX_VALUE.getValue())   ) : bizTemperatureChannel.getMaxValue());
                    //通道已经初始化后 并绑定了设备 才去做 1:N判断(判断是否是高温预警 还是温度异常预警)
                    Integer deviceId = bizTemperatureChannel.getDeviceId();

//                    //温差
//                    Double chaValue = bizTemperatureChannel.getChaValue();
//                    chaValue = chaValue == null ? TempConstant.TEMP_CHA_VALUE : chaValue;

                    //内部实际温度
                    Double realTemp = temperature + chaValue;

                    //温度最大值 (40)
                    Double maxValue = bizTemperatureChannel.getMaxValue();
                    maxValue = maxValue == null ? Double.parseDouble(findDIcValue(TempDictType.TEMP_MAX_VALUE.getValue())) : maxValue;

                    //温度波动值 (35)
                    Double boValue = maxValue - Double.parseDouble(findDIcValue(TempDictType.TEMP_BO_VALUE.getValue()));

                    //1:N 判断故障类型
                    Integer errorType = null;

                    //预警间隔时间
                    Integer tempErrorInterval = Integer.parseInt(findDIcValue(TempDictType.TEMP_ERROR_INTERVAL.getValue()));

                    if (realTemp >= maxValue) {
                        //【温度过高预警】
                        errorType = TempConstant.ERROR_TYPE_ONE;
                        COUNT_MAP.put(gatewayCode + key, 0);

                    } else if (realTemp >= boValue) {

                        //波动计数器
                        Integer count = COUNT_MAP.get(gatewayCode + key);
                        count = count == null ? 0 : count;

                        //包括3次以上达到波动值 定义为 【温度波动异常预警】
                        if (count >= Integer.parseInt(findDIcValue(TempDictType.TEMP_BO_NUMBER.getValue()))) {
                            errorType = TempConstant.ERROR_TYPE_TWO;
                            //波动异常的时间间隔也授变量控制
                            // tempErrorInterval = 0;
                            COUNT_MAP.put(gatewayCode + key, 0);
                        } else {
                            COUNT_MAP.put(gatewayCode + key, ++count);
                        }

                    } else {
                        COUNT_MAP.put(gatewayCode + key, 0);
                    }
                    // log.warn("波动异常时间开始 {} , COUNT_MAP>> {}"
                    // ,DateUtil.format(record.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), COUNT_MAP);
                    //产生异常
                    createError(record, deviceId, errorType, tempErrorInterval);
                }
                //保存记录【biz_temperature_record】
                boolean res = this.save(record);
                //  System.out.println("");
            }
        }
    }


    //初始化温度数据到 【biz_temperature_channel】
    public void findInitChannel(BizTemperatureChannel bizTemperatureChannel, BizTemperatureRecord record) {

        if (ObjectUtil.isNull(bizTemperatureChannel)) {
            //初始化到温度通道表
            bizTemperatureChannel = new BizTemperatureChannel();
            bizTemperatureChannel.setGatewayId(record.getGatewayId());
            bizTemperatureChannel.setGatewayCode(record.getGatewayCode());
            bizTemperatureChannel.setGatewayChannel(record.getGatewayChannel());
            bizTemperatureChannelService.save(bizTemperatureChannel);
        }
    }

    //生成异常
    public void createError(BizTemperatureRecord record, Integer deviceId, Integer errorType, Integer tempErrorInterval) {

        if (ObjectUtil.isNotNull(errorType)) {
            //查询故障存在不？
            BizTemperatureException bizTemperatureException = SpringUtil.getBean(BizTemperatureExceptionService.class).lambdaQuery()
                    .eq(BizTemperatureException::getDeviceId, deviceId)
                    .eq(BizTemperatureException::getGatewayId, record.getGatewayId())
                    .eq(BizTemperatureException::getErrorType, errorType)
                    .eq(BizTemperatureException::getStatus, 0)
                    .orderByDesc(BizTemperatureException::getCreateTime)
                    .last("limit 1")
                    .one();

            //保存故障 【biz_temperature_exception】
            bizTemperatureException = saveException(bizTemperatureException, record, deviceId, errorType, tempErrorInterval);

            //保存故障LOG 【biz_temperature_exception_log】
            //因为LOG一直存 需要故障主表的id
            saveExceptionLog(bizTemperatureException, record);
        }
    }


    //保存故障 返回故障id
    public BizTemperatureException saveException(BizTemperatureException bizTemperatureException, BizTemperatureRecord record, Integer deviceId, Integer errorType, Integer tempErrorInterval) {

        if (ObjectUtil.isNull(bizTemperatureException)) {
            //第一次新故障
            bizTemperatureException = new BizTemperatureException();
            bizTemperatureException.setDeviceId(deviceId);
            bizTemperatureException.setGatewayId(record.getGatewayId());
            bizTemperatureException.setStatus(0);
            bizTemperatureException.setErrorType(errorType);
            bizTemperatureExceptionService.save(bizTemperatureException);

        } else {
            Date beginDate = bizTemperatureException.getCreateTime();
            Date endDate = new Date();
            //2次之间的时间间隔差
            long errorInterval = DateUtil.between(beginDate, endDate, DateUnit.MINUTE);
            //  log.warn("开始时间：{} 第二次时间：{}， 时间间隔；{}"
            //            , DateUtil.format(beginDate, "yyyy-MM-dd HH:mm:ss")
            //            , DateUtil.format(endDate, "yyyy-MM-dd HH:mm:ss")
            //            , errorInterval
            //    );

            //大于报警间隔 再记录一次故障
            if (errorInterval >= tempErrorInterval) {
                //同类型故障 再来一次
                bizTemperatureException = new BizTemperatureException();
                bizTemperatureException.setDeviceId(deviceId);
                bizTemperatureException.setGatewayId(record.getGatewayId());
                bizTemperatureException.setStatus(0);
                bizTemperatureException.setErrorType(errorType);
                bizTemperatureExceptionService.save(bizTemperatureException);
            }
        }
        return bizTemperatureException;
    }


    //保存故障日志
    public void saveExceptionLog(BizTemperatureException bizTemperatureException, BizTemperatureRecord record) {
        BizTemperatureExceptionLog bizTemperatureExceptionLog = new BizTemperatureExceptionLog();
        bizTemperatureExceptionLog.setExceptionId(bizTemperatureException.getId());
        bizTemperatureExceptionLog.setGatewayId(bizTemperatureException.getGatewayId());
        bizTemperatureExceptionLog.setGatewayChannel(record.getGatewayChannel());
        bizTemperatureExceptionLog.setTemperature(record.getTemperature());
        bizTemperatureExceptionLog.setFirstTime(bizTemperatureException.getCreateTime());
        bizTemperatureExceptionLog.setErrorType(bizTemperatureException.getErrorType());
        bizTemperatureExceptionLog.setStatus(bizTemperatureException.getStatus());
        bizTemperatureExceptionLog.setDeviceId(bizTemperatureException.getDeviceId());
        bizTemperatureExceptionLogService.save(bizTemperatureExceptionLog);

    }

    /**
     * 动态获取配置的值
     *
     * @param dictType
     * @return
     */
    public String findDIcValue(String dictType) {
        BizTemperatureConfig one = SpringUtil.getBean(BizTemperatureConfigService.class)
                .lambdaQuery()
                .eq(BizTemperatureConfig::getDictType, dictType)
                .one();
        if (ObjectUtil.isNotNull(one)) {
            return one.getDictValue();
        }
        return null;
    }

    public static void main(String[] args) {
        String ss = TempDictType.TEMP_RECORD_INTERVAL.getValue();
        System.out.println(">>>" + ss);
    /*    Double d = 32.66;
        Integer i = 10;
        Double dd = d + i;
        System.out.println("dd>>>>>>>" + dd);*/


  /*      Date old = DateUtil.parseDateTime("2024-06-11 11:00:00");
        //计算时间差 初始设置 60分钟
        long cha = DateUtil.between(old, new Date(), DateUnit.MINUTE);
        System.out.println("差》》》》》》" + cha);
        // 给定的日期
        Date givenDate = DateUtil.date();
        // 计算30分钟后的日期
        Date dateAfterThirtyMinutes = DateUtil.offsetMinute(givenDate, 30);
        // 输出结果
        System.out.println("给定的日期：" + DateUtil.formatDateTime(givenDate));
        System.out.println("30分钟后的日期：" + DateUtil.formatDateTime(dateAfterThirtyMinutes));*/

    }
}
